package com.bw.mvi.event

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer


/**
 * 1.EventBus 需要添加 注册反注册 接收事件的方法
 * 2.需要自己管理声明周期(手动注册和取消注册) 容易内存泄露
 * LiveData
 *      1.设计上 支持粘性事件(数据版本的控制) 不支持非粘性事件
 *      2.自动关联组件的生命周期
 *
 *如何解决LiveData非粘性事件(如何解决数据倒灌问题)
 *      1.Google官方 SingleLiveEvent 不支持多次订阅
 *      2.使用微信UnPeekLiveData 解决
 *      3.使用反射技术修改订阅版本号和数据版本号，阻止订阅者收到重复数据
 *      4.使用ShareFlow 共享热流
 */
/**
 * 使用观察者设计模式(观察-订阅)
 * 接入 Jetpack中使用
 */
object LiveDataBus {
    /**
     * 不同业务对应不同的BusMutableLiveData
     */
    private val bus = mutableMapOf<String, BusMutableLiveData<Any>>()
    fun <T> getDefault(key: String): BusMutableLiveData<T> {
        if (!bus.containsKey(key)) {
            bus[key] = BusMutableLiveData()
        }
        return bus[key] as BusMutableLiveData<T>
    }
    /**
     * 自定义LiveData 利用反射技术 修改订阅版本号和数据版本号，阻止订阅者收到重复数据(LiveData本身属于粘性事件，会导致数据倒灌)
     */
    class BusMutableLiveData<T> : MutableLiveData<T>() {
        //存储所有订阅方
        private val observersMap = mutableMapOf<Observer<*>,  Observer<*>>()
        /**
         * 支持订阅前台事件
         */
        override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
            super.observe(owner, observer)
            try {
                hookSticky(observer)
            } catch (e: Exception) {
                e.printStackTrace()
            }

        }

        /**
         * 订阅前台粘性事件
         */
        fun observeSticky(owner: LifecycleOwner, observer: Observer<in T>) {
            super.observe(owner, observer) //本身支持粘性事件 不用做特殊处理
        }
        /**
         * 订阅后台事件
         */
        override fun observeForever(observer: Observer<in T>) {
            if(observer in observersMap){
                observersMap[observer] = mObserverWrapper(observer)
            }
            super.observeForever(observersMap[observer] as Observer<in T>)
        }


        /**
         * 订阅后台粘性事件
         */
        fun observeStickyForever(observer: Observer<in T>) {
            super.observeForever(observer)
        }
        override fun removeObserver(observer: Observer<in T>) {
            val observerWrapper: Observer<in T> = if(observersMap.containsKey(observer)){
                observersMap.remove(observer)as Observer<in T>
            }else{
                observer
            }
            super.removeObserver(observer)
        }
        private fun hookSticky(observer: Observer<*>){
            //拿到LiveData的Class字节码文件
            val liveDataClass = LiveData::class.java
            val mVersionField = liveDataClass.getDeclaredField("mVersion").apply {
                isAccessible = true //设置可访问
            }
            var mObserverVersion = mVersionField[this]
            val mObserverFieldMap = liveDataClass.getDeclaredField("mObservers").apply {
                isAccessible = true //设置可访问
            }
            val observers = mObserverFieldMap[this]
            val observerClass: Class<*> = observers.javaClass
            val methodGet = observerClass.getDeclaredMethod("get", Any::class.java).apply {
                isAccessible = true
            }
            //执行GET方法
            val observerObject = methodGet.invoke(observers, observer)
            var subObserverWrapper: Any? = null
            if(observerObject is Map.Entry<*,*>){
                subObserverWrapper = observerObject.value
            }
            //判断空处理
            if(subObserverWrapper == null){
                throw NullPointerException("subObserverWrapper is null")
            }
            //获取父类Class文件
            val observerWrapper :Class<*>? = subObserverWrapper.javaClass.superclass
            //获取数据版本号
            val lastVersionField = observerWrapper!!.getDeclaredField("mLastVersion").apply {
                isAccessible = true
            }
            //修改数据版本号
            lastVersionField[subObserverWrapper] = mObserverVersion
        }
    }
    class mObserverWrapper<T>(private val observer: Observer<T>) : Observer<T> {
        override fun onChanged(value: T) {
            if(isCallOnObserveForever()) return
            observer.onChanged(value)
        }
        private fun isCallOnObserveForever(): Boolean {
            //获取当前线程的堆栈信息
            val threadStack = Thread.currentThread().stackTrace
            for (item in threadStack){
                //判断是否是调用了observeForever
                if("androidx.lifecycle.LiveData" == item.className && "observeForever" == item.methodName){
                    return true
                }
            }
            return false
        }
    }
}
